package com.blue.jdbc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.Assert;

import com.blue.core.dict.annotation.DictClassHandler;
import com.blue.core.file.ClassScanner;
import com.blue.jdbc.annotation.CacheEntity;
import com.blue.jdbc.annotation.CacheId;
import com.blue.jdbc.annotation.CacheVersion;
import com.blue.jdbc.annotation.JdbcTableClassHandler;
import com.blue.jdbc.annotation.LockModeType;
import com.blue.jdbc.annotation.Parser;
import com.blue.jdbc.dialect.IDialect;
import com.blue.jdbc.sql.SqlExtendUtil;
import com.blue.jdbc.sql.SqlUtil;

/**
 * 基于对象的数据库操作
 * 
 * @author zhengj
 * @since 1.0 2011-4-1
 */
public class JdbcObjectTemplate
{
	private static Logger log = LoggerFactory.getLogger(JdbcObjectTemplate.class);

	private final JdbcTemplate jdbcTemplate;
	private final NamedParameterJdbcTemplate nJdbcTemplate;
	private final Parser parser;
	private final IDialect dialect;
	private final ObjectSupport support;
	private final SqlUtil sqlUtil;
	private final SqlExtendUtil sqlExtendUtil;
	private boolean showSql = false;

	public JdbcObjectTemplate(JdbcTemplate jdbcTemplate, IDialect dialect)
	{
		this.dialect = dialect;
		
		this.jdbcTemplate = jdbcTemplate;
		this.nJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
		
		this.support = ObjectSupport.getInstance();
		
		this.parser = Parser.getInstance();
		
		this.sqlUtil = SqlUtil.getInstance();
		sqlUtil.setDialect(dialect);
		
		parser.setSqlUtil(sqlUtil);
		
		sqlExtendUtil = SqlExtendUtil.getInstance();
		sqlExtendUtil.setDialect(dialect);
	}

	/**
	 * 保存对象
	 * 
	 * @param object 列表
	 */
	public int save(Object object)
	{
		return this.save(object, true);
	}

	/**
	 * 保存对象
	 * 
	 * @param object
	 * @param dynamic 空字段是否也写进SQL语句中
	 */
	public int save(Object object, boolean dynamic)
	{
		Assert.notNull(object, "对象不能为空");
		CacheEntity cacheEntity = parser.parse(object.getClass());
		String sql = cacheEntity.getInsertSQL();
		Map<String, Object> map = new HashMap<String, Object>();
		support.generateId(map, object.getClass());
		support.objectToMap(map, object, true);

		if (sql == null || sql.equals("") || dynamic)
		{
			sql = sqlUtil.insertSQL(map, object.getClass());
		}

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		KeyHolder key = new GeneratedKeyHolder();
		int n = nJdbcTemplate.update(sql, new MapSqlParameterSource(map), key);
		support.setId(key, object);
		return n;
	}
	
	/**
	 * 保存对象
	 * 
	 * @param clazz 对象类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return
	 */
	public int saveObject(Class<?> clazz, Object...params)
	{
		Assert.notNull(clazz, "类型不能为空");
		
		String sql = sqlExtendUtil.insertSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Map<String, Object> param = new HashMap<>();
		for (int i = 0; i < params.length; i+=2)
		{
			param.put((String)params[i], params[i + 1]);
		}
		
		return nJdbcTemplate.update(sql, param);
	}
	
	/**
	 * 保存对象列表，默认不产生主键
	 * 
	 * @param objectList 对象列表
	 */
	@SuppressWarnings("unchecked")
	public int[] saveList(List<?> objectList)
	{
		if (objectList == null || objectList.size() == 0)
			return null;

		Object object = objectList.get(0);
		CacheEntity cacheEntity = parser.parse(object.getClass());
		String sql = cacheEntity.getInsertSQL();
		
		List<Map<String, Object>> mapList = new ArrayList<>();
		for (Object obj : objectList)
		{
			Map<String, Object> map = new HashMap<>();
			support.generateId(map, obj.getClass());
			support.objectToMap(map, obj, true);
			mapList.add(map);
		}
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		return nJdbcTemplate.batchUpdate(sql, mapList.toArray(new Map[0]));
	}

	/**
	 * 更新对象
	 * 
	 * @param object
	 */
	public int update(Object object)
	{
		return this.update(object, true);
	}

	/**
	 * 更新对象
	 * 
	 * @param object
	 * @param dynamic 空字段是否也写进SQL语句中
	 */
	public int update(Object object, boolean dynamic)
	{
		Assert.notNull(object, "对象不能为空");
		CacheEntity cacheEntity = parser.parse(object.getClass());
		String sql = cacheEntity.getUpdateSQL();
		Map<String, Object> map = new HashMap<String, Object>();
		support.objectToMap(map, object, false);

		if (sql == null || sql.equals("") || dynamic)
		{
			sql = sqlUtil.updateSQL(map, object.getClass());
		}

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		int n = nJdbcTemplate.update(sql, map);
		if (cacheEntity.getVersion() != null && n == 0)
			throw new VersionException(object.getClass());
		return n;
	}
	
	/**
	 * 更新对象
	 * 
	 * @param clazz 对象类型
	 * @param id 对象主键值
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return
	 */
	public int updateObject(Class<?> clazz, Object id, Object...params)
	{
		Assert.notNull(clazz, "类型不能为空");
		Assert.notNull(id, "ID不能为空");

		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException(clazz.getName() + " 主键个数不为1，不支持该操作");
		
		String sql = sqlExtendUtil.updateSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
			
		CacheId cacheId = cacheEntity.getIdMap().values().iterator().next();
		Map<String, Object> param = new HashMap<>();
		param.put(cacheId.getName(), id);
		for (int i = 0; i < params.length; i+=2)
		{
			param.put((String)params[i], params[i + 1]);
		}
		
		return nJdbcTemplate.update(sql, param);
	}
	
	/**
	 * 更新对象列表
	 * 
	 * @param objectList 对象列表
	 */
	@SuppressWarnings("unchecked")
	public int[] updateList(List<?> objectList)
	{
		if (objectList == null || objectList.size() == 0)
			return null;

		Object object = objectList.get(0);
		CacheEntity cacheEntity = parser.parse(object.getClass());
		String sql = cacheEntity.getUpdateSQL();
		CacheVersion cacheVersion = cacheEntity.getVersion();
		if (cacheVersion != null)
			sql = cacheEntity.getUpdateVersionSQL();
		
		List<Map<String, Object>> mapList = new ArrayList<>();
		for (Object obj : objectList)
		{
			Map<String, Object> map = new HashMap<>();
			support.objectToMap(map, obj, false);
			mapList.add(map);
		}
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		int[] ns = nJdbcTemplate.batchUpdate(sql, mapList.toArray(new Map[0]));
		Arrays.stream(ns).forEach(n ->
		{
			if (cacheEntity.getVersion() != null && n == 0)
				throw new VersionException(object.getClass());
		});
		return ns;
	}
	
	/**
	 * 对象自增长
	 * 
	 * @param clazz 对象类型
	 * @param id 对象主键
	 * @param params [字段名0, 增长值0, 字段名1, 增长值1...]
	 * @return 影响记录数
	 */
	public int inc(Class<?> clazz, Object id, Object...params)
	{
		Assert.notNull(clazz, "类型不能为空");
		Assert.notNull(id, "ID不能为空");

		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException("主键个数不为1，不支持该操作");
		
		String sql = sqlExtendUtil.incSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Object[] objects = new Object[params.length / 2 + 1];
		for (int i = 0; i < objects.length - 1; i++)
		{
			objects[i] = params[i * 2 + 1];
		}
		objects[objects.length - 1] = id;
		
		return jdbcTemplate.update(sql, objects);
	}

	/**
	 * 删除对象
	 * 
	 * @param object 对象
	 * @return 影响数据库记录数
	 */
	public int delete(Object object)
	{
		Assert.notNull(object, "对象不能为空");
		CacheEntity cacheEntity = parser.parse(object.getClass());
		String sql = cacheEntity.getDeleteSQL();
		Map<String, Object> source = support.getId(object);

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		return nJdbcTemplate.update(sql, source);
	}
	
	/**
	 * 根据主键删除对象
	 * 
	 * @param id 主键
	 * @return 影响数据库记录数
	 */
	public int deleteId(Class<?> clazz, Object id)
	{
		Assert.notNull(id, "主键列表不能为空");
		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException("主键个数不为1，不支持该操作");
		
		String sql = cacheEntity.getDeleteSQL();
		CacheId cacheId = cacheEntity.getIdMap().values().iterator().next();
		Map<String, Object> param = new HashMap<>();
		param.put(cacheId.getName(), id);

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		return nJdbcTemplate.update(sql, param);
	}
	
	/**
	 * 根据主键列表删除对象
	 * 
	 * @param clazz 对象类型
	 * @param idList 主键列表
	 */
	public <K, T> int delete(Class<T> clazz, List<K> idList)
	{
		if (idList == null || idList.isEmpty())
			return 0;
		
		Assert.notNull(clazz, "对象类型不能为空");
		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException("主键个数不为1，不支持该操作");
		if (cacheEntity.getDeleteListSQL() == null || cacheEntity.getDeleteListSQL().isEmpty())
			throw new UnsupportedOperationException(cacheEntity.getTable() + " 主键个数不为1，不支持该操作");
		
		if (idList == null || idList.isEmpty())
			return 0;
		
		String sql = String.format(cacheEntity.getDeleteListSQL(), StringUtils.join(idList, ","));

		return jdbcTemplate.update(sql);
	}
	
	/**
	 * 根据字段值删除
	 * 
	 * @param clazz 对象类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 影响记录数
	 */
	public <T> int deleteBy(Class<T> clazz, Object...params)
	{
		Assert.notNull(clazz, "类型不能为空");
		
		String sql = sqlExtendUtil.deleteSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Object[] objects = new Object[params.length / 2];
		for (int i = 0; i < objects.length; i++)
		{
			objects[i] = params[i * 2 + 1];
		}
		
		return jdbcTemplate.update(sql, objects);
	}
	
	/**
	 * 根据主键取得一个对象
	 * 
	 * @param id 单主键
	 * @param clazz 对象类型
	 * @return 对象，不存在返回 null
	 */
	public <T> T get(Class<T> clazz, Object id)
	{
		return this.get(clazz, id, LockModeType.NONE);
	}

	/**
	 * 根据主键取得一个对象
	 * 
	 * @param id 单主键
	 * @param clazz 对象类型
	 * @param type 锁类型
	 * @return 对象，不存在返回 null
	 */
	public <T> T get(Class<T> clazz, Object id, LockModeType type)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		Assert.notNull(id, "对象ID不能为空");
		Assert.notNull(type, "锁类型不能为空");
		
		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException(clazz.getName() + " 主键个数不为1，不支持该操作");
		
		String sql = dialect.lock(cacheEntity.getGetSQL(), type);
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);

		CacheId cacheId = cacheEntity.getIdMap().values().iterator().next();
		Map<String, Object> map = new HashMap<>();
		map.put(cacheId.getColumn(), id);

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		List<T> list = nJdbcTemplate.query(sql, map, mapper);
		if (list == null || list.isEmpty())
			return null;
		else
			return list.get(0);
	}
	
	/**
	 * 根据主键取得对象Map
	 * 
	 * @param clazz 对象类型
	 * @param idList 主键列表
	 * @return 对象Map
	 */
	@SuppressWarnings("unchecked")
	public <K, T> Map<K, T> get(Class<T> clazz, Collection<K> idList)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		CacheEntity cacheEntity = parser.parse(clazz);
		if (cacheEntity.getIdMap().size() != 1)
			throw new IllegalArgumentException(clazz.getName() + " 主键个数不为1，不支持该操作");
		
		if (cacheEntity.getGetListSQL() == null || cacheEntity.getGetListSQL().isEmpty())
			throw new UnsupportedOperationException(cacheEntity.getTable() + " 主键个数不为1，不支持该操作");
		
		Map<K, T> map = new HashMap<>();
		if (idList == null || idList.isEmpty())
			return map;
		
		String sql = String.format(cacheEntity.getGetListSQL(), StringUtils.join(idList, ","));
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);
		
		CacheId cacheId = cacheEntity.getIdMap().values().iterator().next();
		
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		List<T> list = nJdbcTemplate.query(sql, mapper);
		if (list == null || list.isEmpty())
			return map;
		
		for (T obj : list)
		{
			try
			{
				K key = (K)cacheId.getGetterMethod().invoke(obj);
				map.put(key, obj);
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		
		return map;
	}
	
	/**
	 * 根据SQL查询一个对象
	 * 
	 * @param clazz 类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 单个对象，不存在返回 null
	 */
	public <T> T get(Class<T> clazz, String sql, Map<String, Object> param)
	{
		return this.get(clazz, sql, param, LockModeType.NONE);
	}
	
	/**
	 * 根据SQL查询一个对象
	 * 
	 * @param clazz 类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @param type 锁类型
	 * @return 单个对象，不存在返回 null
	 */
	public <T> T get(Class<T> clazz, String sql, Map<String, Object> param, LockModeType type)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		Assert.hasText(sql, "SQL不能为空");
		Assert.notNull(type, "锁类型不能为空");
		
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);
		sql = dialect.lock(dialect.page(sql, 0, 1), type);

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		List<T> list = nJdbcTemplate.query(sql, param, mapper);
		if (list.size() == 0)
			return null;
		else
			return list.get(0);
	}
	
	/**
	 * 根据SQL查询一个对象
	 * 
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 单个对象，不存在返回 null
	 */
	public <T> T get(String sql, T param)
	{
		return this.get(sql, param, LockModeType.NONE);
	}
	
	/**
	 * 根据SQL查询一个对象
	 * 
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @param type 锁类型
	 * @return 单个对象，不存在返回 null
	 */
	public <T> T get(String sql, T param, LockModeType type)
	{
		Assert.hasText(sql, "SQL不能为空");
		Assert.notNull(param, "查询参数不能为空");
		Assert.notNull(type, "加锁类型不能为空");
		
		Map<String, Object> map = new HashMap<>();
		support.objectToMap(map, param, false);
		
		RowMapper<T> mapper = ObjectRowMapper.getInstance(param.getClass());
		sql = dialect.lock(dialect.page(sql, 0, 1), type);
		
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		List<T> list = nJdbcTemplate.query(sql, map, mapper);
		if (list.size() == 0)
			return null;
		else
			return list.get(0);
	}
	
	/**
	 * 查询一个字段
	 * 
	 * @param clazz 对象类型
	 * @param target 字段类型
	 * @param field 字段名称
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 字段值
	 */
	public <T> T getField(Class<?> clazz, Class<T> target, String field, Object...params)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		Assert.notNull(target, "字段类型不能为空");
		Assert.hasText(field, "字段名称不能为空");
		
		String sql = sqlExtendUtil.getFieldSQL(clazz, field, params);
		sql = dialect.page(sql, 0, 1);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Object[] objects = new Object[params.length / 2];
		for (int i = 0; i < objects.length; i++)
		{
			objects[i] = params[i * 2 + 1];
		}
		
		List<T> list = jdbcTemplate.queryForList(sql, target, objects);
		if (list.isEmpty())
			return null;
		
		return list.get(0);
	}
	
	/**
	 * 查询一个对象
	 * 
	 * @param clazz 对象类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 对象
	 */
	public <T> T getObject(Class<T> clazz, Object...params)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);
		String sql = sqlExtendUtil.getSQL(clazz, params);
		sql = dialect.page(sql, 0, 1);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Map<String, Object> param = new HashMap<>();
		for (int i = 0; i < params.length; i+=2)
		{
			param.put((String)params[i], params[i + 1]);
		}
		List<T> list = nJdbcTemplate.query(sql, param, mapper);
		if (list.isEmpty())
			return null;
		
		return list.get(0);
	}
	
	/**
	 * 判断对象某些字段是否存在
	 * 
	 * @param object 对象
	 * @param names 字段列表
	 * @return true表示存在，false表示不存在
	 */
	public boolean exist(Object object, String...names)
	{
		Assert.notNull(object, "对象不能为空");
		Class<?> clazz = object.getClass();
		Map<String, Object> map = new HashMap<>();
		support.objectToMap(map, object, false);
		String sql = sqlExtendUtil.existSQL(map, clazz, names);
		
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
			
		return nJdbcTemplate.queryForObject(sql, map, Boolean.class);
		
	}
	
	/**
	 * 根据SQL查询一个整数
	 * 
	 * @param <T> 类型参数
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 整数
	 */
	public <T> int queryForInt(String sql, T param)
	{
		Assert.hasText(sql, "SQL不能为空");
		Map<String, Object> map = new HashMap<>();
		support.objectToMap(map, param, false);
		
		return this.queryForInt(sql, map);
	}
	
	/**
	 * 根据SQL查询一个整数
	 * 
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 整数
	 */
	public int queryForInt(String sql, Map<String, Object> param)
	{
		Assert.hasText(sql, "SQL不能为空");
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Integer n = nJdbcTemplate.queryForObject(sql, param, Integer.class);
		
		return n == null ? 0 : n.intValue();
	}
	
	/**
	 * 查询记录数
	 * 
	 * @param clazz 类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 记录数
	 */
	public int count(Class<?> clazz, Object...params)
	{
		Assert.notNull(clazz, "类型不能为空");
		
		String sql = sqlExtendUtil.countSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Object[] objects = new Object[params.length / 2];
		for (int i = 0; i < objects.length; i++)
		{
			objects[i] = params[i * 2 + 1];
		}
		
		return jdbcTemplate.queryForObject(sql, Integer.class, objects);
	}

	/**
	 * 根据SQL语句查询列表，以Map方式返回
	 * 
	 * @param sql SQL语句
	 * @param param Map查询参数
	 * @return
	 */
	public List<Map<String, Object>> list(String sql, Map<String, Object> param)
	{
		Assert.hasText(sql, "SQL不能为空");
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		List<Map<String, Object>> list = nJdbcTemplate.queryForList(sql, param);
		ObjectUtil.convert(list);
		return list;
	}

	/**
	 * 根据SQL语句查询列表，以Map方式返回，带分页
	 * 
	 * @param sql SQL语句
	 * @param param Map查询参数
	 * @param start 起始等号
	 * @param size 最大记录数
	 * @return
	 */
	public List<Map<String, Object>> list(String sql, Map<String, Object> param, int start, int size)
	{
		Assert.hasText(sql, "SQL不能为空");
		sql = dialect.page(sql, start, size);

		return this.list(sql, param);
	}
	
	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql)
	{
		return this.list(clazz, sql, new HashMap<String, Object>());
	}

	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql, T param)
	{
		Assert.notNull(clazz, "类型不能为空");
		Assert.hasText(sql, "SQL不能为空");
		Map<String, Object> map = new HashMap<>();
		support.objectToMap(map, param, false);

		return this.list(clazz, sql, map);
	}
	
	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql, Map<String, Object> param)
	{
		Assert.notNull(clazz, "类型不能为空");
		Assert.hasText(sql, "SQL不能为空");
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);

		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);

		List<T> list = nJdbcTemplate.query(sql, param, mapper);
		return list;
	}
	
	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @param start 起始行号
	 * @param size 最大记录数
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql, int start, int size)
	{
		sql = dialect.page(sql, start, size);

		return this.list(clazz, sql, new HashMap<String, Object>());
	}

	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @param start 起始行号
	 * @param size 最大记录数
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql, T param, int start, int size)
	{
		sql = dialect.page(sql, start, size);

		return this.list(clazz, sql, param);
	}
	
	/**
	 * 根据SQL语句查询列表，以对象列表返回
	 * 
	 * @param clazz 对象类型
	 * @param sql SQL语句
	 * @param param 查询参数
	 * @param start 起始行号
	 * @param size 最大记录数
	 * @return 对象列表
	 */
	public <T> List<T> list(Class<T> clazz, String sql, Map<String, Object> param, int start, int size)
	{
		sql = dialect.page(sql, start, size);

		return this.list(clazz, sql, param);
	}
	
	/**
	 * 查询字段列表
	 * 
	 * @param clazz 对象类型
	 * @param target 字段类型
	 * @param field 字段名称
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 字段列表
	 */
	public <T> List<T> listField(Class<?> clazz, Class<T> target, String field, Object...params)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		Assert.notNull(target, "字段类型不能为空");
		Assert.hasText(field, "字段名称不能为空");
		
		String sql = sqlExtendUtil.getFieldSQL(clazz, field, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Object[] objects = new Object[params.length / 2];
		for (int i = 0; i < objects.length; i++)
		{
			objects[i] = params[i * 2 + 1];
		}
		
		List<T> list = jdbcTemplate.queryForList(sql, target, objects);
		return list;
	}
	
	/**
	 * 查询对象列表
	 * 
	 * @param clazz 对象类型
	 * @param params [字段名0, 字段值0, 字段名1, 字段值1...]
	 * @return 对象列表
	 */
	public <T> List<T> listObject(Class<T> clazz, Object...params)
	{
		Assert.notNull(clazz, "对象类型不能为空");
		
		RowMapper<T> mapper = ObjectRowMapper.getInstance(clazz);
		String sql = sqlExtendUtil.getSQL(clazz, params);
		if (showSql)
			System.out.println("JdbcObjectTemplate: " + sql);
		
		Map<String, Object> param = new HashMap<>();
		for (int i = 0; i < params.length; i+=2)
		{
			param.put((String)params[i], params[i + 1]);
		}
		List<T> list = nJdbcTemplate.query(sql, param, mapper);
		return list;
	}
	
	/**
	 * 转义字段
	 * 
	 * @param key
	 * @return
	 */
	public String escape(String key)
	{
		Assert.hasText(key, "字段不能为空");
		return dialect.escape(key);
	}
	
	/**
	 * 取得对象所关联的表名
	 * 
	 * @param clazz 对象类型
	 * @param escape 是否转义
	 * @return 对象所关联的表名
	 */
	public String getTable(Class<?> clazz, boolean escape)
	{
		Assert.notNull(clazz, "类型不能为空");
		CacheEntity entity = parser.parse(clazz);
		String table = entity.getTable();
		return escape ? dialect.escape(table) : table;
	}
	
	/**
	 * 取得对象的主键列名
	 * 
	 * @param clazz 对象类型
	 * @param escape 是否转义
	 * @return 对象主键列名
	 */
	public String getIdColumn(Class<?> clazz, boolean escape)
	{
		Assert.notNull(clazz, "类型不能为空");
		CacheEntity entity = parser.parse(clazz);
		CacheId id = entity.getIdMap().values().iterator().next();
		return escape ? dialect.escape(id.getColumn()) : id.getColumn();
	}

	public void setShowSql(boolean showSql)
	{
		this.showSql = showSql;
	}
	
	public void setScanPackages(List<String> packageList)
	{
		log.info("扫描包：{}", packageList);
		ClassScanner scanner = new ClassScanner();
		scanner.setClassHandler(new JdbcTableClassHandler());
		scanner.scan(true, packageList);
	}

	public void setScanDicts(List<String> packageList)
	{
		packageList.add(0, "com.blue.core.dict");
		log.info("扫描包：{}", packageList);
		ClassScanner scanner = new ClassScanner();
		scanner.setClassHandler(new DictClassHandler());
		scanner.scan(true, packageList);
	}
	
}
